#define DDCLLUA_CORE

#include "ddcl.h"
#include "ddcltimer.h"
#include "ddclmalloc.h"
#include "lua-ddcl.h"

#include <stdio.h>

static int
_getconfig_dduint32(lua_State * L, const char * name, dduint32 * v, int index){
    lua_pushstring(L, name);
    lua_rawget(L, index);
    if(!lua_isnil(L, -1)){
        *v = (dduint32)luaL_checkinteger(L, -1);
    }
    lua_pop(L, 1);
    return 0;
}

static int
l_init (lua_State * L){
    ddcl conf;
    ddcl_default(&conf);
    if (lua_gettop(L) > 0){
        _getconfig_dduint32(L, "worker", &conf.worker, 1);
        _getconfig_dduint32(L, "socket", &conf.socket, 1);
        _getconfig_dduint32(L, "sleep", &conf.sleep, 1);
    }
    int err = ddcl_init(&conf);
    if(err){
        luaL_error(L, ddcl_err(err));
    }
    return 0;
}

static int
l_open (lua_State * L){
    int module = luaL_checkinteger(L, 1);
    int err = ddcl_open(module);
    if(err){
        luaL_error(L, ddcl_err(err));
    }
    return 0;
}

static int
l_open_all (lua_State * L){
    int err = ddcl_open_all();
    if(err){
        luaL_error(L, ddcl_err(err));
    }
    return 0;
}

static int
l_is_open (lua_State * L){
    int module = luaL_checkinteger(L, 1);
    lua_pushboolean(L, ddcl_is_open(module));
    return 1;
}

static int
l_final (lua_State * L){
    ddcl_final();
    return 0;
}

static int
l_now (lua_State * L){
    lua_pushinteger(L, ddcl_now());
    return 1;
}

static int
l_systime (lua_State * L){
    lua_pushinteger(L, ddcl_systime());
    return 1;
}

static int
l_packstring(lua_State * L){
    void * data = lua_touserdata(L, 1);
    if(lua_gettop(L) > 1){
        if(data){
            lua_Integer sz = luaL_checkinteger(L, 2);
            lua_pushlstring(L, (const char *)data, sz);
            return 1;
        }
    }else{
        if(data){
            lua_pushstring(L, (const char *)data);
            return 1;
        }
    }
    return 0;
}

static int
l_malloc (lua_State * L){
    lua_Integer size = luaL_checkinteger(L, 1);
    void * p = ddcl_malloc(size);
    lua_pushlightuserdata(L, p);
    lua_pushinteger(L, size);
    return 2;
}

static int
l_free (lua_State * L){
    if(!lua_islightuserdata(L, 1)){
        return luaL_error(L, "param error #1, lightuserdata got %s",
                lua_typename(L, lua_type(L, 1)));
    }
    ddcl_free(lua_touserdata(L, 1));
    return 0;
}

static luaL_Reg _REG[] = {
    { "init", l_init },
    { "open", l_open },
    { "open_all", l_open_all },
    { "is_open", l_is_open },
    { "final", l_final },
    { "now", l_now },
    { "systime", l_systime },
    { "packstring", l_packstring },
    { "malloc", l_malloc },
    { "free", l_free },
    { NULL, NULL },
};


DDCLLUA int
luaopen_ddcl (lua_State * L){
    luaL_checkversion(L);
    DDLUA_NEWLIB(L, "ddcl", _REG);

    DDLUA_PUSHENUM(L, "TIMER_MODULE", DDCL_TIMER_MODULE);
    DDLUA_PUSHENUM(L, "SERVICE_MODULE", DDCL_SERVICE_MODULE);
    DDLUA_PUSHENUM(L, "SOCKET_MODULE", DDCL_SOCKET_MODULE);
    DDLUA_PUSHENUM(L, "LOG_MODULE", DDCL_LOG_MODULE);
    return 1;
}
